/*
 * Copyright (C) 2017 Samuel Wall
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package uk.co.samuelwall.materialtaptargetprompt.extras;

import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.text.SimpleTextLayout;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import uk.co.samuelwall.materialtaptargetprompt.utils.Constants;
import uk.co.samuelwall.materialtaptargetprompt.utils.DensityUtils;

/**
 * PromptText
 *
 * @since 2021-06-21
 */
public class PromptText implements PromptUIElement {
    RectFloat mTextBounds = new RectFloat();
    float mPrimaryTextLeft;
    float mPrimaryTextLeftChange;
    float mPrimaryTextTop;
    float mSecondaryTextLeft;
    float mSecondaryTextLeftChange;
    float mSecondaryTextOffsetTop;
    SimpleTextLayout mPrimaryTextLayout;
    SimpleTextLayout mSecondaryTextLayout;
    PromptOptions mPromptOptions;
    /**
     * The paint used to draw the primary text.
     */
    Paint mPaintPrimaryText;

    /**
     * The paint used to draw the secondary text.
     */
    Paint mPaintSecondaryText;

    /**
     * The primary text layout alignment.
     * Left, centre or right.
     */
    int mPrimaryTextAlignment;

    /**
     * The secondary text layout alignment.
     * Left, centre or right.
     */
    int mSecondaryTextAlignment;

    boolean isClipToBounds;

    Rect mClipBounds;

    /**
     * PromptText
     */
    public PromptText() {
    }

    /**
     * Get the window position for the prompt text.
     *
     * @return The prompt text bounds.
     */
    public RectFloat getBounds() {
        return mTextBounds;
    }

    /**
     * Recalculates the primary and secondary text positions.
     *
     * @param options    options
     * @param isClip     clipToBounds
     * @param clipBounds clipBounds
     */
    public void prepare(
            PromptOptions options,
            boolean isClip, Rect clipBounds) {
        mPromptOptions = options;
        isClipToBounds = isClip;
        mClipBounds = clipBounds;
        final CharSequence primaryText = options.getPrimaryText();
        if (primaryText != null) {
            mPaintPrimaryText = new Paint();
            final int primaryTextColour = options.getPrimaryTextColour();
            mPaintPrimaryText.setColor(new Color(primaryTextColour));
            mPaintPrimaryText.setAntiAlias(true);
            mPaintPrimaryText.setMultipleLine(true);
            mPaintPrimaryText.setTextSize((int) options.getPrimaryTextSize());
            PromptUtils.setFont(mPaintPrimaryText, options.getPrimaryTextFont(), options.getPrimaryTextFontStyle());
            mPrimaryTextAlignment = PromptUtils.getTextAlignment(options.getResourceFinder().getResources(),
                    options.getPrimaryTextGravity(), primaryText);
        }

        final CharSequence secondaryText = options.getSecondaryText();
        if (secondaryText != null) {
            mPaintSecondaryText = new Paint();
            final int secondaryTextColour = options.getSecondaryTextColour();
            mPaintSecondaryText.setColor(new Color(secondaryTextColour));
            mPaintSecondaryText.setAntiAlias(true);
            mPaintSecondaryText.setMultipleLine(true);
            mPaintSecondaryText.setTextSize((int) options.getSecondaryTextSize());
            PromptUtils.setFont(mPaintSecondaryText, options.getSecondaryTextFont(),
                    options.getSecondaryTextFontStyle());
            mSecondaryTextAlignment = PromptUtils.getTextAlignment(options.getResourceFinder().getResources(),
                    options.getSecondaryTextGravity(), secondaryText);
        }
        final RectFloat focalBounds = options.getPromptFocal().getBounds();
        final float focalCentreX = focalBounds.getCenter().getPointX();
        final float focalCentreY = focalBounds.getCenter().getPointY();

        final boolean isVerticalTextPositionAbove = focalCentreY - clipBounds.getCenterY() > 0;
        final boolean isHorizontalTextPositionLeft = focalCentreX - clipBounds.getCenterX() > 0;

        final float maxWidth = PromptUtils.calculateMaxWidth(options.getMaxTextWidth(),
                isClip ? clipBounds : null,
                options.getResourceFinder().getPromptParentView().getWidth(),
                options.getTextPadding());
        createTextLayout(options, maxWidth, 1);
        final float primaryTextWidth = PromptUtils.calculateMaxTextWidth(mPrimaryTextLayout);
        final float secondaryTextWidth = PromptUtils.calculateMaxTextWidth(mSecondaryTextLayout);
        final float textWidth = Math.max(primaryTextWidth, secondaryTextWidth);
        final float focalPadding = options.getFocalPadding();
        final float textPadding = options.getTextPadding();

        if (PromptUtils.containsInset(clipBounds,
                Constants.NUM_88
                        * (int) DensityUtils.getDeviceAttr(options.getResourceFinder().getContext()).getAttributes().densityPixels,
                (int) focalCentreX, (int) focalCentreY)) {
            mPrimaryTextLeft = clipBounds.left;
            final float width = Math.min(textWidth, maxWidth);
            if (isHorizontalTextPositionLeft) {
                mPrimaryTextLeft = focalCentreX - width + focalPadding;
            } else {
                mPrimaryTextLeft = focalCentreX - width - focalPadding;
            }
            if (mPrimaryTextLeft < clipBounds.left + textPadding) {
                mPrimaryTextLeft = clipBounds.left + textPadding;
            }
            if (mPrimaryTextLeft + width > clipBounds.right - textPadding) {
                mPrimaryTextLeft = clipBounds.right - textPadding - width;
            }
        } else {
            if (isHorizontalTextPositionLeft) {
                mPrimaryTextLeft = (isClip ? clipBounds.right
                        : options.getResourceFinder().getPromptParentView().getRight()) - textPadding - textWidth;
            } else {
                mPrimaryTextLeft = (isClip ? clipBounds.left
                        : options.getResourceFinder().getPromptParentView().getLeft()) + textPadding;
            }
        }

        if (isVerticalTextPositionAbove) {
            mPrimaryTextTop = focalBounds.top - focalPadding;
            if (mPrimaryTextLayout != null) {
                mPrimaryTextTop -= mPrimaryTextLayout.getHeight();
            }
        } else {
            mPrimaryTextTop = focalBounds.bottom + focalPadding;
        }

        float primaryTextHeight = 0;
        if (mPrimaryTextLayout != null) {
            primaryTextHeight = mPrimaryTextLayout.getHeight();
        }
        float textHeight;
        if (mSecondaryTextLayout != null) {
            textHeight = mSecondaryTextLayout.getHeight();
            if (isVerticalTextPositionAbove) {
                mPrimaryTextTop -= textHeight;
                if (mPrimaryTextLayout != null) {
                    mPrimaryTextTop -= options.getTextSeparation();
                }
            }

            if (mPrimaryTextLayout != null) {
                mSecondaryTextOffsetTop = primaryTextHeight + options.getTextSeparation();
            }
            textHeight += mSecondaryTextOffsetTop;
        } else {
            textHeight = primaryTextHeight;
        }

        mSecondaryTextLeft = mPrimaryTextLeft;
        mPrimaryTextLeftChange = 0;
        mSecondaryTextLeftChange = 0;
        final float change = maxWidth - textWidth;
        if (PromptUtils.isRtlText(mPrimaryTextLayout, options.getResourceFinder().getResources())) {
            mPrimaryTextLeftChange = change;
        }
        if (PromptUtils.isRtlText(mSecondaryTextLayout, options.getResourceFinder().getResources())) {
            mSecondaryTextLeftChange = change;
        }
        mTextBounds.left = mPrimaryTextLeft;
        mTextBounds.top = mPrimaryTextTop;
        mTextBounds.right = mTextBounds.left + textWidth;
        mTextBounds.bottom = mTextBounds.top + textHeight;
    }

    /**
     * Creates the text layouts for the primary and secondary text.
     *
     * @param options       options
     * @param maxWidth      The maximum width that the text can be
     * @param alphaModifier alphaModifier
     */
    void createTextLayout(
            final PromptOptions options, final float maxWidth,
            final float alphaModifier) {
        CharSequence primaryText = options.getPrimaryText();
        if (primaryText != null) {
            mPrimaryTextLayout = PromptUtils.createStaticTextLayout(primaryText,
                    mPaintPrimaryText, (int) maxWidth, mPrimaryTextAlignment,
                    (float) Color.alpha(mPaintPrimaryText.getColor().getValue()) / Constants.NUM_255 * alphaModifier);
        } else {
            mPrimaryTextLayout = null;
        }
        CharSequence secondaryText = options.getSecondaryText();
        if (secondaryText != null) {
            mSecondaryTextLayout = PromptUtils.createStaticTextLayout(secondaryText,
                    mPaintSecondaryText, (int) maxWidth, mSecondaryTextAlignment,
                    (float) Color.alpha(mPaintSecondaryText.getColor().getValue()) / Constants.NUM_255 * alphaModifier);
        } else {
            mSecondaryTextLayout = null;
        }
    }

    @Override
    public void update(float revealModifier, float alphaModifier) {
        final float maxWidth = PromptUtils.calculateMaxWidth(mPromptOptions.getMaxTextWidth(),
                isClipToBounds ? mClipBounds : null,
                mPromptOptions.getResourceFinder().getPromptParentView().getWidth(),
                mPromptOptions.getTextPadding());
        createTextLayout(mPromptOptions, maxWidth, alphaModifier);
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.translate(mPrimaryTextLeft - mPrimaryTextLeftChange, mPrimaryTextTop);
        if (mPrimaryTextLayout != null) {
            mPrimaryTextLayout.drawText(canvas);
        }
        if (mSecondaryTextLayout != null) {
            canvas.translate(-(mPrimaryTextLeft - mPrimaryTextLeftChange)
                    + mSecondaryTextLeft - mSecondaryTextLeftChange, mSecondaryTextOffsetTop);
            mSecondaryTextLayout.drawText(canvas);
        }
    }

    @Override
    public boolean contains(float x, float y) {
        return mTextBounds.isInclude(x, y);
    }
}
